package com.linln.admin.app.service.impl;

import com.linln.admin.app.constants.AppConstants;
import com.linln.admin.app.constants.TaskTypeEnum;
import com.linln.admin.app.domain.*;
import com.linln.admin.app.repository.*;
import com.linln.admin.app.service.VersionService;
import com.linln.admin.sync.domain.FlowNacos;
import com.linln.admin.sync.domain.FlowSql;
import com.linln.admin.sync.domain.NacosDefaultConf;
import com.linln.admin.sync.repository.FlowNacosRepository;
import com.linln.admin.sync.repository.FlowSqlRepository;
import com.linln.admin.sync.repository.NacosDefaultConfRepository;
import com.linln.admin.system.domain.TaskQueue;
import com.linln.admin.system.repository.TaskQueueRepository;
import com.linln.common.data.PageSort;
import com.linln.common.enums.StatusEnum;
import com.linln.common.exception.ResultException;
import com.linln.common.utils.HttpServletUtil;
import com.linln.component.shiro.ShiroUtil;
import com.linln.component.thymeleaf.utility.DictUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.*;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author 陶富成
 * @date 2021/07/09
 */
@Service("versionServiceImpl")//这个名称不要改，在EntityUtils中使用到了，包括下面的getById方法名也不要改
public class VersionServiceImpl implements VersionService {

    @Autowired
    private VersionRepository versionRepository;
    @Autowired
    private VersionAppRepository versionAppRepository;
    @Autowired
    private TaskQueueRepository taskQueueRepository;
    @Autowired
    private InfoRepository infoRepository;
    @Autowired
    private ProductionLineRepository productionLineRepository;

    @Resource
    private FlowNacosRepository nacosRepository;
    @Resource
    private FlowSqlRepository sqlRepository;
    @Resource
    private NacosDefaultConfRepository defaultConfRepository;
    @Resource
    private VersionMemberRepository memberRepository;

    private static final String JDBC_PREFIX = "jdbc:";
    private static final String mysqlProtocolKey = JDBC_PREFIX + "mysql://";
    private static final String mysqlDomainKey = "mysql.domain";

    private String addContentKey = "add";//内容新增的汇总key
    private String changeContentKey = "change";//内容改变的汇总key

    /**
     * 根据ID查询数据
     *
     * @param id 主键ID
     */
    @Override
    public AppVersion getById(Long id) {
        if (id == null) {
            return null;
        }
        return versionRepository.findById(id).orElse(null);
    }

    /**
     * 获取分页列表数据
     *
     * @param example 查询实例
     * @return 返回分页数据
     */
    @Override
    public Page<AppVersion> getPageList(Example<AppVersion> example) {
        // 创建分页对象，注意，如果条件中发布状态选择的是已发布，则按发布时间降序排列
        PageRequest page = PageSort.pageRequest();
        if (AppConstants.YES.equals(example.getProbe().getPublished())) {
            page = PageSort.pageRequest("publishtime", Sort.Direction.DESC);
        }
        AppVersion version = example.getProbe();

        //不是管理员，只能查看自己参与的版本信息
        final Long userId = (version.getLeader_id() == null && !ShiroUtil.isAdmin()) ? ShiroUtil.getSubject().getId() : version.getLeader_id();

        return versionRepository.findAll(new Specification<AppVersion>() {

            public Predicate toPredicate(Root<AppVersion> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                String prodLineId = HttpServletUtil.getParameter("prodLineId");
                List<Predicate> preList = new ArrayList<>();
                if (StringUtils.isNotBlank(version.getVersion())) {
                    preList.add(cb.like(root.get("version").as(String.class), "%" + version.getVersion() + "%"));
                }
                if (StringUtils.isNotBlank(version.getDemand_title())) {
                    preList.add(cb.like(root.get("demand_title").as(String.class), "%" + version.getDemand_title() + "%"));
                }
                if (StringUtils.isNotBlank(version.getDemand_url())) {
                    preList.add(cb.like(root.get("demand_url").as(String.class), "%" + version.getDemand_url() + "%"));
                }
                if (StringUtils.isNotBlank(version.getCo_release_branch())) {
                    preList.add(cb.equal(root.get("co_release_branch").as(String.class), version.getCo_release_branch()));
                }
                if (StringUtils.isNotBlank(version.getPublished())) {
                    preList.add(cb.equal(root.get("published").as(String.class), version.getPublished()));
                }

                if (userId != null) {
                    //创建子查询，返回的类型
                    Subquery<VersionMember> subquery = query.subquery(VersionMember.class);
                    //子查询 要查询哪个实体
                    Root<VersionMember> subRoot = subquery.from(VersionMember.class);
                    subquery.where(subRoot.get("user_id").in(userId));
                    //子查询要查询哪个字段
                    subquery = subquery.select(subRoot.get("version_id"));
                    //将子查询与父查询和到一起
                    preList.add(cb.and(root.get("id").in(subquery)));
                }

                if (StringUtils.isNotBlank(prodLineId)) {
                    //创建子查询，返回的类型
                    Subquery<AppInfo> subquery = query.subquery(AppInfo.class);//从app中查询到
                    //子查询 要查询哪个实体
                    Root<AppInfo> subRoot = subquery.from(AppInfo.class);
                    subquery.where(subRoot.get("prod_line_id").in(prodLineId));
                    //子查询要查询哪个字段
                    subquery = subquery.select(subRoot.get("id"));
                    //将子查询再与version_app关联
                    Subquery<VersionApp> subquery1 = query.subquery(VersionApp.class);//从version_app中查询到
                    Root<VersionApp> subRoot1 = subquery1.from(VersionApp.class);
                    subquery1.where(subRoot1.get("app_id").in(subquery));
                    subquery1 = subquery1.select(subRoot1.get("version_id"));
                    //将子查询与父查询和到一起
                    preList.add(cb.and(root.get("id").in(subquery1)));
                }

                Predicate[] pres = new Predicate[preList.size()];
                return query.where(preList.toArray(pres)).getRestriction();
            }

        }, page);
    }

    /**
     * 保存数据
     *
     * @param appVersion 实体对象
     */
    @Override
    @Transactional
    public AppVersion save(AppVersion appVersion, String[] memberIds) {
        //验证：一旦切过分支代码，则版本号、是否为修复，都不可以修改
        Long leaderId = appVersion.getLeader_id();
        if (hasDevBranch(appVersion.getId())) {
            AppVersion beAppVersion = getById(appVersion.getId());//有开发分支，那肯定存在版本信息
            if (!StringUtils.equals(beAppVersion.getVersion(), appVersion.getVersion())) {
                throw new IllegalArgumentException("开发分支已存在，版本号不可修改！");
            }
            if (!StringUtils.equals(beAppVersion.getHotfix_flag(), appVersion.getHotfix_flag())) {
                throw new IllegalArgumentException("开发分支已存在，版本类型（是否修复版本）不可修改！");
            }
            leaderId = beAppVersion.getLeader_id();
        }
        if (!Pattern.matches("[a-zA-Z0-9\\-_]+", appVersion.getVersion().trim())) {
            throw new IllegalArgumentException("版本号只能是字母和数字及-/，其它符号不允许！");
        }
        //处理demand_url
        //查看版本信息是否已经存在
        Long versionId = appVersion.getId() == null ? 0L : appVersion.getId();
        if (versionRepository.countByVersionAndStatusAndIdNot(appVersion.getVersion(), StatusEnum.OK.getCode(), versionId) > 0) {
            throw new IllegalArgumentException("版本号已经存在！");
        }
        if (versionRepository.countByDemandUrlAndStatusAndIdNot(appVersion.getDemand_url(), StatusEnum.OK.getCode(), versionId) > 0) {
            String ver = "";
            try {
                ver = getDevVersionByDemandUrl(appVersion.getDemand_url()).getVersion();
            } catch (Exception e) {
            }
            throw new IllegalArgumentException("该需求的版本已经存在：" + ver + "！");
        }
        versionRepository.save(appVersion);

        //开始添加成员
        memberRepository.deleteByVersionId(appVersion.getId());
        if (memberIds == null || memberIds.length < 1) {
            memberIds = new String[]{};
        }
        for (String id : memberIds) {
            if (StringUtils.isBlank(id) || !StringUtils.isNumeric(id)) {
                continue;
            }
            saveMember(appVersion.getId(), Long.parseLong(id));
        }
        if (memberIds.length < 1 || !Arrays.asList(memberIds).contains(leaderId + "")) {
            saveMember(appVersion.getId(), leaderId);
        }
        return appVersion;
    }

    private void saveMember(Long versionId, long userId) {
        VersionMember member = new VersionMember();
        member.setVersion_id(versionId);
        member.setUser_id(userId);
        memberRepository.save(member);
    }

    /**
     * 获取还在开发状态，未发布的版本信息
     *
     * @param demandUrl
     * @return
     */
    private AppVersion getDevVersionByDemandUrl(String demandUrl) {
        if (StringUtils.isBlank(demandUrl)) {
            return null;
        }
        AppVersion
                version = new AppVersion();
        version.setDemand_url(demandUrl);
        version.setPublished(AppConstants.NO);
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("demand_url", match -> match.contains());
        Example<AppVersion> example = Example.of(version, matcher);
        Page<AppVersion> page = getPageList(example);
        return page.hasContent() ? page.getContent().get(0) : null;
    }

    /**
     * 状态(启用，冻结，删除)/批量状态处理
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(StatusEnum statusEnum, List<Long> idList) {
        if (idList == null || idList.isEmpty()) {
            return false;
        }
        //看一下是否关联了应用，如果关联了应用，那就不能删除
        if (statusEnum.compareTo(StatusEnum.DELETE) == 0) {
            for (Long id : idList) {
                if (versionAppRepository.countByVersionId(id) > 0) {
                    throw new IllegalStateException("版本中有应用项目关联，不能删除!");
                }
            }
        }
        return versionRepository.updateStatus(statusEnum.getCode(), idList) > 0;
    }

    /**
     * 创建一个release分支，然后将dev分支合并到release分支上，如果现在的开发分支有合并冲突，不允许创建
     *
     * @param versionId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createReleaseBranch(long versionId) {
        AppVersion version = getById(versionId);
        if (version == null || AppConstants.YES.equals(version.getHotfix_flag())) {
            throw new IllegalArgumentException("版本信息不正确或修复版本不需要创建release，拒绝创建release分支！");
        }
        //从prod切出release，然后将dev合并到release
        if (hasConflict(versionId)) {
            throw new IllegalArgumentException("当前版本有冲突未解决，拒绝创建release分支！");
        }
        version.setCo_release_branch(AppConstants.YES);
        versionRepository.save(version);

        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(versionId);
        tq.setType(TaskTypeEnum.CREATE_RELEASE_BRANCH.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        return tq.getId();
    }

    /**
     * 将指定版本中的所有发布分支的代码都检测一遍，检查发布分支代码规范：pom文件中是否有snapshot引用、pom文件中版本号改变规则等
     *
     * @param versionId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long branchPmdCheck(long versionId) {
        //判断这个版本有没有切出release分支
        AppVersion ver = getById(versionId);
        if (ver == null || (AppConstants.NO.equals(ver.getCo_release_branch()) && AppConstants.NO.equals(ver.getHotfix_flag()))) {
            throw new IllegalArgumentException("不是release分支或修复版本，没有检查的必要！");
        }
        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(versionId);
        tq.setType(TaskTypeEnum.CHECK_PMD.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        return tq.getId();
    }

    /**
     * 将版本置为已发布状态。要做的事情：将release代码合并到prod，合并成功后，将prod代码合并到当前所有在开发的版本中
     *
     * @param versionId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long doPublished(long versionId) {
        AppVersion ver = getById(versionId);
        if (ver == null || (AppConstants.NO.equals(ver.getCo_release_branch()) && AppConstants.NO.equals(ver.getHotfix_flag()))) {
            throw new IllegalArgumentException("版本信息或状态不正确！");
        }
        if (hasConflict(versionId)) {
            throw new IllegalArgumentException("代码有冲突，请解决完冲突才能上线！");
        }
        ver.setPublished(AppConstants.YES);
        ver.setOnprod(AppConstants.YES);
        ver.setPublishtime(new Date());
        versionRepository.save(ver);

        TaskQueue tq = new TaskQueue();
        tq.setRelate_id(versionId);
        tq.setType(TaskTypeEnum.PUBLISHED.getType());
        tq.setStatus(AppConstants.TASK_STATUS_NEW);
        tq.setCreate_date(new Date());
        taskQueueRepository.save(tq);
        return tq.getId();
    }

    @Override
    public boolean hasDevBranch(Long versionId) {
        if (versionId == null) {
            return false;
        }
        return versionAppRepository.countByVersionId(versionId) > 0;
    }

    /**
     * 是否存在合并代码冲突
     *
     * @param versoinId
     * @return
     */
    @Override
    public boolean hasConflict(Long versoinId) {
        if (versoinId == null) {
            return false;
        }
        return versionAppRepository.countConflict(versoinId) > 0;
    }

    @Override
    public Map<AppInfo, List<AppVersion>> combineAppCurrencyInfo() {
        List<VersionApp> vas = versionAppRepository.findAllDevAppAndVersion();
        Map<Long, AppInfo> apps = new HashMap<>();
        Map<Long, List<AppVersion>> appVers = new HashMap<>();
        List<Long> containsAppVersionIds = new ArrayList<>();
        Long userId = !ShiroUtil.isAdmin() ? ShiroUtil.getSubject().getId() : null;
        for (VersionApp va : vas) {
            Long appId = va.getApp_id();
            AppInfo app = apps.get(appId);
            if (app == null) {
                Optional<AppInfo> a = infoRepository.findById(appId);
                if (!a.isPresent()) {
                    continue;
                }
                app = a.get();
                apps.put(appId, app);
            }
            List<AppVersion> list = appVers.get(appId);
            if (list == null) {
                list = new ArrayList<>();
            }
            Long verId = va.getVersion_id();
            AppVersion v = getById(verId);
            if (v == null) {
                continue;
            }
            if (userId != null && getUserIdsByVersionId(verId).contains(userId)) {
                containsAppVersionIds.add(verId);//当前登录人所在的版本
            }
            list.add(v);
            appVers.put(appId, list);
        }
        Map<AppInfo, List<AppVersion>> ret = new HashMap<>();
        if (appVers.size() > 0) {
            for (Long appId : appVers.keySet()) {
                AppInfo app = apps.get(appId);
                List<AppVersion> vers = appVers.get(appId);
                if (vers == null || vers.size() < 2) {
                    continue;//没有两个及以上的版本引用的应用，不是共用的
                }
                ret.put(app, vers);
            }

            //把与自己无关的分组去除
            if (userId != null) {
                List<AppInfo> deleteApps = new ArrayList<>();
                for (AppInfo app : ret.keySet()) {
                    List<AppVersion> vers = ret.get(app);
                    boolean containsCurUser = false;
                    for (AppVersion ver : vers) {
                        if (containsAppVersionIds.contains(ver.getId())) {
                            containsCurUser = true;
                            break;
                        }
                    }
                    if (!containsCurUser) {
                        deleteApps.add(app);
                    }
                }
                if (deleteApps.size() > 0) {
                    deleteApps.forEach((de) -> {
                        ret.remove(de);
                    });
                }
            }
        }
        return ret;
    }

    /**
     * 判断发布后的项目能不能再重新打开。逻辑：看最后一次的发布记录中是不是当前项目。
     *
     * @param versionId
     * @return
     */
    @Override
    public boolean canReopen(Long versionId) {
        AppVersion version = getById(versionId);
        if (version == null) {
            return false;
        }
        if (AppConstants.NO.equals(version.getPublished())) {
            return false;//还没有发布，就不需要重开
        }
        return true;//一律可以重开项目
//        AppVersion db = versionRepository.findLatestByOnprod(AppConstants.YES);
//        if (db == null) {
//            return true;//如果没有发布的，则可以直接重开（虽然不正常，因为状态是已发布，怎么会没有已发布记录呢）
//        }
//        return versionId.compareTo(db.getId()) == 0;//最后发布的和当前的相同，则表示可以重开
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reopen(long versionId) {
        if (!canReopen(versionId)) {
            throw new IllegalArgumentException("不能重开，原因可能是当前已经有了新的发布，或者已经重开了");
        }
        AppVersion version = getById(versionId);
        version.setPublished(AppConstants.NO);
        versionRepository.save(version);
    }


    @Transactional
    @Override
    public boolean discard(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        try {
            versionRepository.discardByIds(ids);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public List<AppVersion> getAllDevVersions() {
        List<AppVersion> vers = versionRepository.findAllDevVers();
        List<AppVersion> ret = new ArrayList<>();
        if (vers == null) {
            return ret;
        }
        for (AppVersion ver : vers) {
            AppVersion one = new AppVersion();
            one.setId(ver.getId());
            one.setVersion(ver.getDemand_title() + " (" + ver.getVersion() + ")");
            ret.add(one);
        }
        return ret;
    }

    @Override
    public String combinePublishProfiles(Long versionId, String env, String profile) {
        if (versionId == null) {
            throw new ResultException(400, "版本号没有指定");
        }

        if ("1".equals(profile)) {//nacos
            List<FlowNacos> confs = nacosRepository.findByVersion_id(versionId);
            if (confs == null) {
                return "";
            }
            return combineWithGroup(env, confs);
        } else if ("2".equals(profile)) {//SQL
            StringBuilder str = new StringBuilder();
            List<FlowSql> list = sqlRepository.findByVersion_id(versionId);
            if (list == null) {
                return str.toString();
            }
            for (FlowSql sql : list) {
                if (StringUtils.isBlank(sql.getContent())) {
                    continue;
                }
                if (str.length() > 0) {
                    str.append("\n");
                    str.append("--  " + sql.getTitle());
                    str.append("\n");
                }
                str.append(sql.getContent());
            }
            return str.toString();
        } else {
            throw new ResultException(400, "资料类型没有指定");
        }
    }

    @Override
    public List<Long> getUserIdsByVersionId(Long versionId) {
        if (versionId == null) {
            return null;
        }
        return memberRepository.findVersionMembers(versionId);
    }

    @Override
    public String getProductionTitles(Long versionId) {
        List<VersionApp> verApps = versionAppRepository.findByVersionId(versionId);
        if (verApps == null || verApps.isEmpty()) {
            return "";
        }
        List<Long> ids = new Stack<>();
        for (VersionApp app : verApps) {
            if (app == null) {
                continue;
            }
            ids.add(app.getApp_id());
        }
        if (ids.isEmpty()) {
            return "";
        }
        List<AppInfo> apps = infoRepository.findAllById(ids);
        if (apps == null || apps.isEmpty()) {
            return "";
        }
        Set<Long> aids = new HashSet<>();
        for (AppInfo app : apps) {
            if (app == null) {
                continue;
            }
            aids.add(app.getProd_line_id());
        }
        if (aids.isEmpty()) {
            return "";
        }
        List<ProductionLine> prods = productionLineRepository.findAllById(aids);
        if (prods == null || prods.isEmpty()) {
            return "";
        }
        StringBuilder ret = new StringBuilder();
        for (ProductionLine prod : prods) {
            if (ret.length() > 0) {
                ret.append(" , ");
            }
            ret.append(prod.getTitle());
        }
        return ret.toString();
    }

    /**
     * 分组汇总并返回成String给textarea显示
     *
     * @param env
     * @param confs
     * @return
     */
    private String combineWithGroup(String env, List<FlowNacos> confs) {
        // 按照dataId分组、是否新增分组。
        Map<String, Map<String, LinkedHashMap<String, String>>> dataIdProps = new HashMap<>();
        Map<String, FlowNacos> dataIdConfs = new HashMap<>();
        for (FlowNacos conf : confs) {
            String dataId = conf.getData_id() + "@" + conf.getGroup_id();
            Map<String, LinkedHashMap<String, String>> props = dataIdProps.get(dataId);
            if (props == null) {
                props = new HashMap<>();
            }

            extracteContent(addContentKey, props, conf.getAdd_content());
            extracteContent(changeContentKey, props, conf.getChange_content());

            dataIdProps.put(dataId, props);
            dataIdConfs.put(dataId, conf);
        }
        //开始将其中的内容替换成对应环境的值
        replaceDefaultConf(dataIdProps, env);
        //输出内容
        StringBuilder str = new StringBuilder();
        for (String dataId : dataIdProps.keySet()) {
            FlowNacos conf = dataIdConfs.get(dataId);
            if (str.length() > 0) {
                str.append("\n\n");
                str.append("=================配置文件之间的分隔线==================");
                str.append("\n\n");
            }
            str.append("· ");
            if (AppConstants.YES.equals(conf.getAdd_flag())) {
                str.append("新增");
            } else {
                str.append("修改");
            }
            str.append("配置文件：");
            if (AppConstants.YES.equals(conf.getAdd_flag())) {
                str.append("\nData ID: " + conf.getData_id());
                str.append("\nGroup : " + conf.getGroup_id());
                str.append("\n配置格式：Properties");
                str.append("\n\n\n");
            } else {
                str.append("Data ID: 【" + conf.getData_id() + "】");
                str.append("里面的内容：\n");
            }
            Map<String, LinkedHashMap<String, String>> props = dataIdProps.get(dataId);

            outputToHtml(props, addContentKey, str, "新增以下内容");
            str.append("\n\n");
            outputToHtml(props, changeContentKey, str, "修改以下key对应的内容");
        }

        return str.toString();
    }

    /**
     * 输出到html展示的格式
     *
     * @param props
     * @param contentKey
     * @param str
     */
    private void outputToHtml(Map<String, LinkedHashMap<String, String>> props, String contentKey, StringBuilder str, String title) {
        LinkedHashMap<String, String> content = props.get(contentKey);
        if (content == null || content.isEmpty()) {
            return;
        }
        str.append("【" + title + "】\n");
        for (String key : content.keySet()) {
            String val = content.get(key);
            if (key.endsWith("+")) {
                str.append("# 在 key是" + key.substring(0, key.length() - 1) + " 的值后面追加内容：\n");
                str.append(val);
            } else {
                str.append(key);
                if (!key.startsWith("#")) {
                    str.append("=" + val);
                }
            }
            str.append("\n");
        }
    }

    private void extracteContent(String addContentKey, Map<String, LinkedHashMap<String, String>> props, String content) {
        LinkedHashMap<String, String> properties = props.get(addContentKey);
        if (StringUtils.isBlank(content)) {
            return;
        }
        if (properties == null) {
            properties = new LinkedHashMap();
        }

        LinkedHashMap<String, String> parsedProps = toProperties(content);
        for (String key : parsedProps.keySet()) {
            if (properties.containsKey(key)) {
                throw new ResultException(400, "key[" + key + "]定义重复了！");
            }
        }
        properties.putAll(parsedProps);
        props.put(addContentKey, properties);
    }

    /**
     * 将内容转换为properties格式
     *
     * @param content
     * @return
     */
    private LinkedHashMap<String, String> toProperties(String content) {
        LinkedHashMap<String, String> parsedProps = new LinkedHashMap();
        if (StringUtils.isBlank(content)) {
            return parsedProps;
        }
        for (String line : content.split("\n")) {
            if (StringUtils.isBlank(line)) {
                continue;
            }
            if (line.startsWith("#")) {//注释的话，啥也不干
                parsedProps.put(line, "");
                continue;
            }
            String[] parts = line.split("=", 2);
            String key = parts[0].trim();
            String value = parts.length == 2 ? parts[1].trim() : "";
            String val = parsedProps.get(key);
            if (val != null) {
                if (key.endsWith("+")) {//累加，就合并内容
                    value = value + val;
                } else {
                    throw new ResultException(400, "key[" + key + "]定义重复了！");
                }
            }
            parsedProps.put(key, value);
        }
        return parsedProps;
    }

    /**
     * 使用默认配置的值对当前值进行替换！
     *
     * @param env
     * @return
     * @throws IOException
     */
    private void replaceDefaultConf(Map<String, Map<String, LinkedHashMap<String, String>>> dataIdProps, String env) {
        NacosDefaultConf defaultConf = defaultConfRepository.findFirstByEnv_type(env);
        if (defaultConf == null || StringUtils.isBlank(defaultConf.getContent())) {
            return;
        }
        Properties defaultPro = new Properties();
        try {
            defaultPro.load(new StringReader(defaultConf.getContent()));
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (String dataId : dataIdProps.keySet()) {
            Map<String, LinkedHashMap<String, String>> one = dataIdProps.get(dataId);
            if (one == null || one.isEmpty()) {
                continue;
            }

            LinkedHashMap<String, String> properties = one.get(addContentKey);
            replaceWithDefault(env, defaultPro, properties);

        }
    }

    /**
     * 替换默认配置中的
     *
     * @param env
     * @param defaultPro
     * @param properties
     */
    public static void replaceWithDefault(String env, Properties defaultPro, Map<String, String> properties) {
        if (properties == null || properties.isEmpty()) {
            return;
        }
        for (String origKey : properties.keySet()) {
            String key = origKey;
            String origVal = properties.get(origKey);

            if (key.endsWith("+")) {//如果是累加的内容，要将这个特殊符号去除，防止无法正确识别
                key = key.substring(0, key.length() - 1).trim();
            }

            String defVal = defaultPro.getProperty(key);

            if (key.startsWith("spring.cloud.stream.bindings.") && key.endsWith(".destination")) {
                //对于MQ的topic，pre和prod环境下的要特殊处理
                defVal = defaultPro.getProperty("spring.cloud.stream.bindings.destination");
            } else if (key.equals("spring.datasource.url")) {
                //URL的替换方式不一样，因为有库名
                String mysqlDomain = defaultPro.getProperty(mysqlDomainKey);
                if (StringUtils.isBlank(origVal)) {
                    continue;
                }
                String tmp = origVal.replace("\\:", ":").replace("\\=", "=");
                tmp = tmp.substring(JDBC_PREFIX.length());
                try {
                    URI uri = new URI(tmp);
                    String path = uri.getPath();
                    if (!mysqlDomain.startsWith(mysqlProtocolKey)) {
                        mysqlDomain = mysqlProtocolKey + mysqlDomain;
                    }
                    defVal = mysqlDomain + path + "?" + (tmp.contains("?") ? tmp.substring(tmp.indexOf("?") + 1) : "");
                    if (!defVal.contains("allowPublicKeyRetrieval")) {
                        defVal += "&allowPublicKeyRetrieval=true";
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
            Map<String, String> domainMap = DictUtil.value("ENV_DOMAINS");
            // origVal里面的域名进行自动替换
            String tarDomain = domainMap.get(env);
            if (StringUtils.isNotBlank(tarDomain)) {
                for (String domain : domainMap.values()) {
                    origVal = origVal.replace(domain, tarDomain);
                }
            }
            properties.put(origKey, StringUtils.defaultIfEmpty(defVal, origVal));
        }
    }
}